using System;
using System.Collections.Generic;
using System.Configuration.Provider;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Web.Configuration;
using System.Web.Security;

namespace System.Web.Core
{
    public abstract class MemberProvider : ProviderBase
    {
        #region Abstract Members

        public abstract Member GetMember(string memberName);
        public abstract List<Member> GetMembers();
        public abstract List<Member> GetMembersByMemberId(Guid memberId);
        public abstract void CreateMember(Member member);
        public abstract void DeleteMember(Guid memberId, string memberName);
        public abstract void ChangeMemberPassword(Member member, string newPassword);
        public abstract string ResetMemberPassword(Member member);
        public abstract bool ValidateMember(Guid memberId, string password);
        public abstract bool ValidateMember(string memberName, string password);
        
        #endregion //Abstract Functions

        #region Public Members

        public string EncodePassword(string pass, int passwordFormat, string salt)
        {
            if (passwordFormat == 0)
            {
                return pass;
            }
            byte[] bIn = Encoding.Unicode.GetBytes(pass);
            byte[] bSalt = Convert.FromBase64String(salt);
            byte[] bAll = new byte[bSalt.Length + bIn.Length];
            byte[] bRet = null;

            Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
            Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
            if (passwordFormat == 1)
            {
                HashAlgorithm s = HashAlgorithm.Create(Membership.HashAlgorithmType);
                bRet = s.ComputeHash(bAll);
            }
            else if (passwordFormat == 2)
            {
                bRet = EncryptPassword(bAll);
            }
            else
            {
                throw new ProviderException("Invalid password format.");
            }
            return Convert.ToBase64String(bRet);
        }
        public string UnEncodePassword(string pass, int passwordFormat)
        {
            switch (passwordFormat)
            {
                case 0:
                    return pass;
                case 1:
                    throw new ProviderException("Can not decode hashed password.");
                case 2:
                    byte[] bIn = Convert.FromBase64String(pass);
                    byte[] bRet = DecryptPassword(bIn);
                    if (bRet == null)
                        return null;
                    return Encoding.Unicode.GetString(bRet, 16, bRet.Length - 16);
                default:
                    throw new ProviderException("Invalid password format.");
            }
        }
        public virtual byte[] DecryptPassword(byte[] encodedPassword)
        {
            Type machineKeySection = typeof(MachineKeySection);
            Type[] paramTypes = new Type[] { typeof(bool), typeof(byte[]), typeof(byte[]), typeof(int), typeof(int) };
            MethodInfo encryptOrDecryptData = machineKeySection.GetMethod("EncryptOrDecryptData", BindingFlags.Static | BindingFlags.NonPublic, null, paramTypes, null);

            return (byte[])encryptOrDecryptData.Invoke(null, new object[] { false, encodedPassword, null, 0, encodedPassword.Length });
        }
        public virtual byte[] EncryptPassword(byte[] password)
        {
            Type machineKeySection = typeof(MachineKeySection);
            Type[] paramTypes = new Type[] { typeof(bool), typeof(byte[]), typeof(byte[]), typeof(int), typeof(int) };
            MethodInfo encryptOrDecryptData = machineKeySection.GetMethod("EncryptOrDecryptData", BindingFlags.Static | BindingFlags.NonPublic, null, paramTypes, null);

            return (byte[])encryptOrDecryptData.Invoke(null, new object[] { true, password, null, 0, password.Length });
        }
        public string GenerateSalt()
        {
            byte[] entity = new byte[0x10];
            new RNGCryptoServiceProvider().GetBytes(entity);
            return Convert.ToBase64String(entity);
        }

        #endregion
    }
}